<template>
  <van-nav-bar title="与 AI 聊天" fixed placeholder safe-area-inset-top />
  <div class="chat-container">
    <van-cell-group>
      <div v-for="(message, index) in messages" :key="index">
        <van-cell :title-style="{ flex: 0 }" :class="{ 'user-message': message.isUser, 'ai-message': !message.isUser }">
          <template #title>
            <span>{{ message.isUser ? '你' : 'AI' }}</span>
          </template>
          <template #default>
            <div v-if="message.isUser">{{ message.text }}</div>
            <div v-else>
              <div v-if="message.isTyping">{{ message.text }}</div>
              <div v-else-if="message.text" v-html="parseMarkdown(message.text)"></div>
            </div>
          </template>
        </van-cell>
      </div>
    </van-cell-group>
    <van-field v-model="userInput" placeholder="输入消息..." @keyup.enter="sendMessage" autosize clearable autofocus
      class="user-input">
      <template #button>
        <van-button size="small" type="primary" @click="sendMessage">发送</van-button>
      </template>
    </van-field>
    <van-button size="normal" type="primary" class="voice-button" plain @touchstart="voiceButtonActive = true"
      @touchend="voiceButtonActive = false" @touchcancel="voiceButtonActive = false" @click="startVoiceInput"
      :class="{ active: voiceButtonActive, fixed }"
      :style="currentUserTypes === 0 ? { width: '80vw', height: '50vh', fontSize: '15vw' } : {}">
      语音输入
    </van-button>

    <!-- 语音输入弹窗 -->
    <section class="fixed-box" id="fixed-box">
      <div class="fixed-main">
        <button class="fixed-close" id="close-btn" @click="stopVoiceInput"></button>
        <div id="fixed-txt">Hello! 请说出你想说话</div>
        <div class="fixed-icon">
          <img src="../../assets/voice.png" alt="图片" />
        </div>
      </div>
    </section>
    <van-back-top bottom="10vh" />
  </div>
</template>

<script setup>
import { withAIChat } from "@/api/AIChat";


import { ref, onMounted, watch, onBeforeUnmount } from 'vue';
import { showFailToast } from 'vant';
import useUserStore from '@/store/user';
import MarkdownIt from 'markdown-it';

const md = new MarkdownIt()
const messages = ref([
  { text: '你好，请问有什么可以帮助你的吗？', isUser: false }
]);
const userInput = ref('');
const voiceButtonActive = ref(false);

const userStore = useUserStore();

// 获取当前用户身份
const currentUserTypes = userStore.userInfo.types;

/* 按钮 */
const fixed = ref(true);

const delay = (ms) => {
  return new Promise(resolve => setTimeout(resolve, ms));
}
const parseMarkdown = (text) => {
  return md.render(text);
}

// 文字转语音
const synth = window.speechSynthesis;
const msg = ref(new SpeechSynthesisUtterance());
const voices = window.speechSynthesis.getVoices();
const voiceToVoice = voices[2];
const text = ref(messages.value[messages.value.length - 1].text);



const playVoice = () => {
  handleSpeak(text.value); // 传入需要播放的文字
};

const handleSpeak = (text) => {
  if (voice) {
        msg.value.voice = voiceToVoice;
    }
  msg.value.text = text; // 文字内容
  msg.value.lang = "zh-CN"; // 使用的语言：中文
  msg.value.volume = 10; // 声音音量：1
  msg.value.rate = 1; // 语速：1
  msg.value.pitch = 1; // 音高：1
  synth.speak(msg.value); // 播放
};

const handleStop = (e) => {
  msg.value.text = e;
  synth.cancel(msg.value);
};

// 使用 watch 监听 text 的变化，并在变化时重新创建 msg
watch(text, (newValue, oldValue) => {
  if (newValue !== oldValue) {
    msg.value = new SpeechSynthesisUtterance(); // 重新创建 msg
    handleSpeak(newValue); // 播放新的文本
  }
});

// 在 onMounted 生命周期钩子中调用 playVoice 函数
onMounted(() => {
  if (currentUserTypes == 0) {
    playVoice();
  }
});

onBeforeUnmount(() => {
  // 停止语音识别
  handleStop()
});

// 发送消息
const sendMessage = async () => {
  if (userInput.value.trim() !== '') {
    messages.value.push({ text: userInput.value, isUser: true });
    messages.value.push({ text: "机器人正在疯狂手打中...", isTyping: true });
    // AI回复
    withAIChat(userStore.userInfo.userid, userInput.value).then(res => {
      const msg = res.data;
      // messages.value.push({ text: res.data, isUser: false });
      if (currentUserTypes == 0) {
        text.value = res.data; // 最新一条消息的文字内容
      }
      setTimeout(async () => {
      if (msg) {
        
        messages.value.push({ text: "", isUser: false });
        messages.value = [...messages.value.filter(msg => !msg.isTyping)]; // 清除正在输入状态
        for (let i = 0; i < msg.length; i++) {
          await delay(70); // 等待一段时间再添加下一个字
          
          
          messages.value = [...messages.value.slice(0, -1), { text: msg.slice(0, i + 1), isUser: false }];

        }
      }
    }, 1000)
    }).catch(() => {
      if (currentUserTypes == 0) {
        text.value = '对不起，AI回复失败，请稍后再试'; // 最新一条消息的文字内容
        return;
      }
      showFailToast('AI回复失败');
    });
    userInput.value = '';
  } else {
    showFailToast('请输入消息');
  }
  /*  */
  const emp = currentUserTypes === 1 ? 350 : 1200;
  const b = window.innerHeight - chatUserInput.getBoundingClientRect().bottom
  if (b < emp) {
    fixed.value = false;
  }
};

// 语音输入

let times = null;

// 实例化迅飞语音听写（流式版）WebAPI
const voice = new Voice({

  // 服务接口认证信息 注：apiKey 和 apiSecret 字符串的长度都差不多，请不要填错了哦！
  appId: '0f52ec0b',
  apiSecret: 'MmQwNmM5Y2U2ZDUzZjE4ZjQ4NTJhMDBi',
  apiKey: 'cda6f997d5ecd0829de9eb04a6d16907',

  onWillStatusChange: function (oldStatus, newStatus) {
    //可以在这里进行页面中一些交互逻辑处理：注：倒计时（语音听写只有60s）,录音的动画，按钮交互等！
    fixedBox.style.display = 'block';
  },
  onTextChange: function (text) {
    //监听识别结果的变化
    userInput.value = text
    fixedTxt.innerText = text;

    // 3秒钟内没有说话，就自动关闭
    if (text) {
      clearTimeout(times);
      times = setTimeout(() => {
        voice.stop()
        fixedBox.style.display = 'none';
      }, 3000);
    }
  }
});

// 开始识别方法
// voice.start();

// 关闭识别
// voice.stop();

// 开始语音输入
const startVoiceInput = () => {
  // 开始语音识别
  voice.start();
  fixedBox.style.display = 'block';
  // 在此处添加语音转文字的逻辑，将转换后的文字输入到用户的输入框中
  // userInput.value = '这里是语音转换后的文字';
}

// 停止语音输入
const stopVoiceInput = () => {
  // 停止语音识别
  voice.stop();
  fixedBox.style.display = 'none';
}

let fixedBox = null
let fixedTxt = null
let chatUserInput = null;
onMounted(() => {
  chatUserInput = document.querySelector('.user-input');
  fixedBox = document.querySelector('#fixed-box');
  fixedTxt = document.querySelector('#fixed-txt');
});


</script>

<style scoped lang="scss">
.chat-container {
  margin: 10px auto;
  display: flex;
  flex-direction: column;
  align-items: center;

  .van-cell-group {
    width: 100%;

    .user-message {
      text-align: left;
      margin-bottom: 10px;
      padding: 10px;
      background-color: #e2f3ff;
    }

    .ai-message {
      text-align: left;
      margin-bottom: 10px;
      padding: 10px;
      background-color: #f5f5f5;
    }
  }

  .user-input {
    margin-top: 20px;
    border: 1px solid #999;
    font-size: 16px;
    padding: 10px;
  }

  .voice-button {
    margin-top: 20px;
    margin-bottom: 20px;

    &.fixed {
      position: fixed;
      bottom: 70px;
      margin-bottom: 0;
    }

    &.active {
      background-color: #1989fa;
      color: #fff;
    }
  }

  .fixed-box {
    box-sizing: border-box;
    display: none;
    position: fixed;
    top: 0px;
    right: 0px;
    bottom: 0px;
    left: 0px;
    border: .04rem solid #e0e7ff;
    background: rgba(16, 22, 62, .2);
  }

  .fixed-close {
    position: absolute;
    top: 0px;
    right: 0px;
    padding: 24px;
    width: 20px;
    height: 20px;
    border: none;
    background: url() no-repeat center center;
    background-size: 20px;
    transition: all .5s;
    cursor: pointer;
    outline: none;
  }

  .fixed-close:hover {
    transform: rotate(270deg);
    -webkit-transform: rotate(270deg);
  }


  .fixed-main {
    box-sizing: border-box;
    position: absolute;
    left: 20%;
    bottom: 0px;
    padding: 30px;
    width: 60%;
    height: 240px;
    font-size: 18px;
    background: white;
    border: 2px solid #e0e7ff;
    border-radius: 5px 5px 0px 0px;
    overflow-y: auto;
  }

  .fixed-icon {
    box-sizing: border-box;
    display: flex;
    justify-content: center;
    align-items: center;
    position: absolute;
    top: 50%;
    left: 50%;
    margin-top: -50px;
    margin-left: -50px;
    width: 100px;
    height: 100px;
    background: linear-gradient(115deg, #56d8e4 5%, #9f01ea 95%);
    border: 1px solid #e0e7ff;
    border-radius: 50%;
  }

  .fixed-icon::before {
    content: "";
    position: absolute;
    display: inline-block;
    width: 100px;
    height: 100px;
    border: 1px solid #9f01ea;
    box-shadow: 0px 0px 6px 0px #9f01ea;
    border-radius: 50%;
    animation: move 1.5s infinite;
  }

  .fixed-icon::after {
    content: "";
    position: absolute;
    display: inline-block;
    width: 100px;
    height: 100px;
    border: 1px solid #56d8e4;
    box-shadow: 0px 0px 6px 0px #56d8e4;
    border-radius: 50%;
    animation: move 1.5s .5s infinite;

  }

  .fixed-icon img {
    width: 30px;
    height: 50px;
  }

  @keyframes move {
    0% {
      opacity: 1;
      transform: scale(1);
    }

    100% {
      opacity: 0;
      transform: scale(2);
    }
  }

  ::-webkit-scrollbar {
    width: 6px;
    height: 6px;
    background-color: #f9f9f9;
  }

  ::-webkit-scrollbar-thumb {
    border-radius: 6px;
    background-color: #187cff;
  }
}
</style>
